/*
 * Author: Honrun
 */
#include "stm32f4xx_hal.h"
#include "stm32f4xx_LL_i2c.h"
#include "stdio.h"

#include "DevicesDelay.h"
#include "DevicesIIC.h"


/* I2C handler declaration */
I2C_HandleTypeDef ex_IIC1Handle = {0};
I2C_HandleTypeDef ex_IIC2Handle = {0};
I2C_HandleTypeDef ex_IIC3Handle = {0};



void vIIC1Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct = {0};
    HAL_StatusTypeDef HAL_Error = HAL_OK;

    /* Enable GPIO TX/RX clock */
    __HAL_RCC_GPIOB_CLK_ENABLE();

    /* Enable I2C1 clock */
    __HAL_RCC_I2C1_CLK_ENABLE();

    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7 | GPIO_PIN_8, GPIO_PIN_SET);

    /* I2C TX GPIO pin configuration  */
    GPIO_InitStruct.Pin       = GPIO_PIN_7 | GPIO_PIN_8;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* Configure the I2C peripheral */
    ex_IIC1Handle.Instance             = I2C1;
    ex_IIC1Handle.Init.AddressingMode  = I2C_ADDRESSINGMODE_7BIT;
    ex_IIC1Handle.Init.ClockSpeed      = I2C1_SPEED;
    ex_IIC1Handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    ex_IIC1Handle.Init.DutyCycle       = I2C_DUTYCYCLE_2;
    ex_IIC1Handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    ex_IIC1Handle.Init.NoStretchMode   = I2C_NOSTRETCH_DISABLE;
    ex_IIC1Handle.Init.OwnAddress1     = I2C1_SLAVE_ADDRESS7;
    ex_IIC1Handle.Init.OwnAddress2     = 0xFE;
    if((HAL_Error = HAL_I2C_Init(&ex_IIC1Handle)) != HAL_OK)
        printf("HAL_I2C_Init IIC1 error: 0x%08X\r\n", HAL_Error);
}

void vIIC1DeInit(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct = {0};
    int8_t i = 0;

    /* Enable GPIO TX/RX clock */
    __HAL_RCC_GPIOB_CLK_ENABLE();

    /* Enable I2C1 clock */
    __HAL_RCC_I2C1_CLK_ENABLE();

    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7 | GPIO_PIN_8, GPIO_PIN_SET);

    /* I2C TX GPIO pin configuration  */
    GPIO_InitStruct.Pin       = GPIO_PIN_7 | GPIO_PIN_8;
    GPIO_InitStruct.Mode      = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* 发送9个时钟，以解除死锁 */
    for(i = 0; i < 9; ++i)
    {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);
        vDelayMs(1);
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);
        vDelayMs(1);
    }

    LL_I2C_EnableReset(I2C1);
    LL_I2C_DisableReset(I2C1);
}

void vIIC2Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct = {0};
    HAL_StatusTypeDef HAL_Error = HAL_OK;

    /* Enable GPIO TX/RX clock */
    __HAL_RCC_GPIOB_CLK_ENABLE();

    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9 | GPIO_PIN_10, GPIO_PIN_SET);

    /* I2C TX GPIO pin configuration  */
    GPIO_InitStruct.Pin       = GPIO_PIN_10;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* I2C TX GPIO pin configuration  */
    GPIO_InitStruct.Pin       = GPIO_PIN_9;
    GPIO_InitStruct.Alternate = GPIO_AF9_I2C2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* Enable I2C1 clock */
    __HAL_RCC_I2C2_CLK_ENABLE();

    /* Configure the I2C peripheral */
    ex_IIC2Handle.Instance             = I2C2;
    ex_IIC2Handle.Init.AddressingMode  = I2C_ADDRESSINGMODE_7BIT;
    ex_IIC2Handle.Init.ClockSpeed      = I2C2_SPEED;
    ex_IIC2Handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    ex_IIC2Handle.Init.DutyCycle       = I2C_DUTYCYCLE_2;
    ex_IIC2Handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    ex_IIC2Handle.Init.NoStretchMode   = I2C_NOSTRETCH_DISABLE;
    ex_IIC2Handle.Init.OwnAddress1     = I2C2_SLAVE_ADDRESS7;
    ex_IIC2Handle.Init.OwnAddress2     = 0xFE;
    if((HAL_Error = HAL_I2C_Init(&ex_IIC2Handle)) != HAL_OK)
        printf("HAL_I2C_Init IIC2 error: 0x%08X\r\n", HAL_Error);
}

void vIIC2DeInit(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct = {0};
    int8_t i = 0;

    /* Enable GPIO TX/RX clock */
    __HAL_RCC_GPIOB_CLK_ENABLE();

    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9 | GPIO_PIN_10, GPIO_PIN_SET);

    /* I2C TX GPIO pin configuration  */
    GPIO_InitStruct.Pin       = GPIO_PIN_9 | GPIO_PIN_10;
    GPIO_InitStruct.Mode      = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* 发送9个时钟，以解除死锁 */
    for(i = 0; i < 9; ++i)
    {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET);
        vDelayMs(1);
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);
        vDelayMs(1);
    }

    LL_I2C_EnableReset(I2C2);
    LL_I2C_DisableReset(I2C2);
}

void vIIC3Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct = {0};
    HAL_StatusTypeDef HAL_Error = HAL_OK;

    /* Enable GPIO TX/RX clock */
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();

    /* Enable I2C1 clock */
    __HAL_RCC_I2C3_CLK_ENABLE();

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_SET);

    /* I2C TX GPIO pin configuration  */
    GPIO_InitStruct.Pin       = GPIO_PIN_8;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin       = GPIO_PIN_9;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* Configure the I2C peripheral */
    ex_IIC3Handle.Instance             = I2C3;
    ex_IIC3Handle.Init.AddressingMode  = I2C_ADDRESSINGMODE_7BIT;
    ex_IIC3Handle.Init.ClockSpeed      = I2C3_SPEED;
    ex_IIC3Handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    ex_IIC3Handle.Init.DutyCycle       = I2C_DUTYCYCLE_2;
    ex_IIC3Handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    ex_IIC3Handle.Init.NoStretchMode   = I2C_NOSTRETCH_DISABLE;
    ex_IIC3Handle.Init.OwnAddress1     = I2C3_SLAVE_ADDRESS7;
    ex_IIC3Handle.Init.OwnAddress2     = 0xFE;
    if((HAL_Error = HAL_I2C_Init(&ex_IIC3Handle)) != HAL_OK)
        printf("HAL_I2C_Init IIC3 error: 0x%08X\r\n", HAL_Error);
}

void vIIC3DeInit(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct = {0};
    int8_t i = 0;

    /* Enable GPIO TX/RX clock */
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();

    /* Enable I2C1 clock */
    __HAL_RCC_I2C3_CLK_ENABLE();

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_SET);

    /* I2C TX GPIO pin configuration  */
    GPIO_InitStruct.Pin       = GPIO_PIN_8;
    GPIO_InitStruct.Mode      = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin       = GPIO_PIN_9;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* 发送9个时钟，以解除死锁 */
    for(i = 0; i < 9; ++i)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
        vDelayMs(1);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
        vDelayMs(1);
    }

    LL_I2C_EnableReset(I2C3);
    LL_I2C_DisableReset(I2C3);
}


int8_t cIICWriteDatas(I2C_HandleTypeDef *hi2c, uint16_t usIDAddr, uint16_t usRegAddr, uint8_t* pBuffer, int32_t iLength)
{
    HAL_StatusTypeDef HAL_Error = HAL_OK;

    if((HAL_Error = HAL_I2C_IsDeviceReady(hi2c, usIDAddr, 2, 10)) == HAL_OK)
    {
        HAL_Error = HAL_I2C_Mem_Write(hi2c, usIDAddr, usRegAddr, I2C_MEMADD_SIZE_8BIT, pBuffer, iLength, 10);
    }
    else
    {
        printf("cIICWriteDatas HAL_Error: %08X\r\n", HAL_Error);
        if(((uint32_t)hi2c) == ((uint32_t)(&ex_IIC1Handle)))
        {
            vIIC1DeInit();
            vIIC1Init();
        }
        else if(((uint32_t)hi2c) == ((uint32_t)(&ex_IIC2Handle)))
        {
            vIIC2DeInit();
            vIIC2Init();
        }
        else if(((uint32_t)hi2c) == ((uint32_t)(&ex_IIC3Handle)))
        {
            vIIC3DeInit();
            vIIC3Init();
        }
    }

    return HAL_Error;
}

int8_t cIICWriteByte(I2C_HandleTypeDef *hi2c, uint16_t usIDAddr, uint16_t usRegAddr, uint8_t ucByte)
{
    return cIICWriteDatas(hi2c, usIDAddr, usRegAddr, &ucByte, 1);
}

int8_t cIICReadDatas(I2C_HandleTypeDef *hi2c, uint16_t usIDAddr, uint16_t usRegAddr, uint8_t* pBuffer, int32_t iLength)
{
    HAL_StatusTypeDef HAL_Error = HAL_OK;

    if((HAL_Error = HAL_I2C_IsDeviceReady(hi2c, usIDAddr, 2, 10)) == HAL_OK)
    {
        HAL_Error = HAL_I2C_Mem_Read(hi2c, usIDAddr, usRegAddr, I2C_MEMADD_SIZE_8BIT, pBuffer, iLength, 10);
    }
    else
    {
        printf("cIICReadDatas HAL_Error: %08X\r\n", HAL_Error);
        if(((uint32_t)hi2c) == ((uint32_t)(&ex_IIC1Handle)))
        {
            vIIC1DeInit();
            vIIC1Init();
        }
        else if(((uint32_t)hi2c) == ((uint32_t)(&ex_IIC2Handle)))
        {
            vIIC2DeInit();
            vIIC2Init();
        }
        else if(((uint32_t)hi2c) == ((uint32_t)(&ex_IIC3Handle)))
        {
            vIIC3DeInit();
            vIIC3Init();
        }
    }

    return HAL_Error;
}

int8_t cIICReadByte(I2C_HandleTypeDef *hi2c, uint16_t usIDAddr, uint16_t usRegAddr, uint8_t *pucByte)
{
    return cIICReadDatas(hi2c, usIDAddr, usRegAddr, pucByte, 1);
}
